﻿#region Copyright ©2008-2009, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: kalus $
// Last Changed Date     $LastChangedDate: 2009-06-18 17:18:03 +0200 (Thu, 18 Jun 2009) $
// Last Changed Revision $Rev: 213 $
//
// ====================================================================================================
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Tum.CollabXT.VModellXT.Resources;

namespace Tum.CollabXT.VModellXT
{
    public class VModellXTProcessProvider : IProcessProvider
    {
        #region Private Members (data structure)
        private List<IActivity> _Activities;
        private List<ITask> _Tasks;
        private List<IProduct> _Products;
        private List<IRole> _Roles;
        private List<IDiscipline> _Disciplines;
        private List<IMilestone> _Milestones;
        private List<ITopic> _Topics;
        private List<IProcessElementDependency> _Dependencies;

        private string _Name;
        private string _Description;

        private Dictionary<string, object> _ExtendedData = new Dictionary<string,object>();

        /// <summary>
        /// Path of the VModellXT.xml.
        /// </summary>
        public string VModellFile
        {
            get { return _VModellFile; }
            set { _VModellFile = value; }
        }
        private string _VModellFile = null;

        /// <summary>
        /// Path of the project file to be read.
        /// </summary>
        public string ProjectFile
        {
            get { return _ProjectFile; }
            set { _ProjectFile = value; }
        }
        private string _ProjectFile = null;


        /// <summary>
        /// Collection of all "Vorgensbaustein"-IDs of this project
        /// </summary>
        private ICollection<string> ProjectVbIdList;
        #endregion


        public static string GetProviderName()
        {
            return Language.ProviderInfo_Name;
        }

        public static string GetProviderDescription()
        {
            return Language.ProviderInfo_Description;
        }

        public static string GetProviderAuthor()
        {
            return "© 2009 TU München";
        }


        public VModellXTProcessProvider() { }

        #region IProcessProvider Member: Init
        public void Initialize(Log log)
        {
            log.AddEntry(Language.Loading_PluginInfo);
            log.AddEntry(Language.Loading_Copyright);
            log.AddSeperator();


            if (VModellFile == null)
                throw new VMXTException(Language.Error_Inititalizing_NoVmxt);

            if (ProjectFile == null)
                InitializeWithoutVMP(log);
            else
                LoadVMPFile(log);

            log.AddEntry(Language.Loading_CompletedSuccessfully);
        }


        /// <summary>
        /// Initializes the process provider for V-Modell XT. The provider is
        /// initialized using the whole model in XML-file format.
        /// </summary>

        /// <param name="log">Log to be used.</param>
        private void InitializeWithoutVMP(Log log)
        {
            if (log == null)
                throw new NullReferenceException("Log must not be null.");

            _Name = "V-Modell XT Project";
            _Description = "";

            XmlDocument modelDocument = new XmlDocument();
            modelDocument.Load(VModellFile);

            LoadDecisionGates(modelDocument, log);
            LoadProducts(modelDocument, log);
            LoadDependencies(modelDocument, log);
            LoadActivities(modelDocument, log);
            LoadTasks(modelDocument, log);
            LoadRoles(modelDocument, log);
            LoadDisciplines(modelDocument, log);
        }

        /// <summary>
        /// Initializes all structures with the data given in the VMP file.
        /// </summary>
        /// <param name="log">Log to be used.</param>
        private void LoadVMPFile(Log log)
        {
            ///TODO: Add DescriptionRaw to all objects - where applicable

            log.AddEntry(Language.Loading_Initializing);
            XmlDocument modelDocument = new XmlDocument();
            modelDocument.Load(VModellFile);

            XmlDocument vmpDocument = new XmlDocument();
            vmpDocument.Load(ProjectFile);

            //Load process name and description
            _Name = Helper.ThrowExceptionWhenNull<XmlNode>(vmpDocument.SelectSingleNode(Queries.VMP_GetProjectName), string.Format(Language.Error_Parsing_NoProjectName, Queries.VMP_GetProjectName)).InnerText;
            _Description = Helper.ThrowExceptionWhenNull<XmlNode>(modelDocument.SelectSingleNode(Queries.MDL_GetModelDescription), string.Format(Language.Error_Parsing_NoDescription, Queries.MDL_GetModelDescription)).InnerText;
            _Description = Helper.StripHtmlString(_Description);

            LoadVBs(modelDocument, vmpDocument, log);

            log.AddEntry(Language.Loading_DecisionGates);
            LoadDecisionGates(modelDocument, vmpDocument, log);

            log.AddEntry(Language.Loading_Products);
            LoadProducts(modelDocument, vmpDocument, log);

            log.AddEntry(Language.Loading_Roles);
            LoadRoles(modelDocument, log);

            log.AddEntry(Language.Loading_Dependencies);
            LoadDependencies(modelDocument, log);

            log.AddEntry(Language.Loading_Topics);
            LoadTopics(modelDocument, log);

            log.AddEntry(Language.Loading_Activities);
            LoadActivities(modelDocument, log);

            log.AddEntry(Language.Loading_Tasks);
            LoadTasks(modelDocument, log);

            log.AddEntry(Language.Loading_Disciplines);
            LoadDisciplines(modelDocument, log);
        }

        /// <summary>
        /// Loads "Vorgehensbausteine" from a VMP-file
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// /// <param name="vmpDocument">VMP document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadVBs(XmlDocument modelDocument, XmlDocument vmpDocument, Log log)
        {
            ProjectVbIdList = new HashSet<string>();

            XmlNodeList vbNodes = vmpDocument.SelectNodes(Queries.VMP_GetVBs);
            foreach (XmlNode curVBNode in vbNodes)
                ProjectVbIdList.Add(curVBNode.Attributes["link"].Value);
        }


        /// <summary>
        /// Loads milestones from a VMP file.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="vmpDocument">VMP document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadDecisionGates(XmlDocument modelDocument, XmlDocument vmpDocument, Log log)
        {
            _Milestones = new List<IMilestone>();

            int mainStatusNr = 0;
            int iterationNr = 0;
            bool inIteration = false;

            XmlNodeList milestoneInformationNodes = vmpDocument.SelectNodes(Queries.VMP_GetMilestones);
            if (milestoneInformationNodes != null)
            {
                foreach (XmlNode curMilestoneNode in milestoneInformationNodes)
                {
                    try
                    {
                        DecisionGate decisionGate = new DecisionGate();

                        //Get milestone data
                        decisionGate.Id = curMilestoneNode.Attributes["id"].Value; //Only set temporarily. Is updated later, if possible
                        decisionGate.Name = curMilestoneNode.SelectSingleNode("Name").InnerText;
                        decisionGate.ScheduledDate = DateTime.Parse(curMilestoneNode.SelectSingleNode("Datum").InnerText);

                        int scheduleNumber = 0;
                        if(int.TryParse(curMilestoneNode.SelectSingleNode("Nummer").InnerText, out scheduleNumber))
                            decisionGate.ScheduleNumber = scheduleNumber;

                        #region Save predecessor ids
                        var predecessorList = new List<string>();
                        decisionGate.ExtendedData["__VMXT_PredecessorList"] = predecessorList;

                        try
                        {
                            var predecessorNodes = curMilestoneNode.SelectNodes("Vorgänger/MSRef");
                            foreach (XmlNode curPredecessor in predecessorNodes)
                                predecessorList.Add(curPredecessor.Attributes["link"].Value);
                        }
                        catch { } 
                        #endregion

                        //## Get type and description of this decision gate
                        //Get taskId of the "Ablaufentscheidungspunkt"
                        var epRef = curMilestoneNode.SelectSingleNode(Queries.VMP_GetAEPRefFromMilestone);
                        if (epRef != null)
                        {
                            string progressReferenceID = epRef.Attributes["link"].Value;

                            //Get decision gate reference taskId
                            string dgReferenceID = modelDocument.SelectSingleNode(String.Format(Queries.MDL_GetDecisionGateReferenceId, progressReferenceID)).Attributes["link"].Value;

                            //Set taskId to decision gate taskId
                            decisionGate.Id = dgReferenceID;

                            //Get type and description of the dg
                            decisionGate.TypeName = modelDocument.SelectSingleNode(String.Format(Queries.MDL_GetDecisionGateType, dgReferenceID)).InnerText;
                            decisionGate.Description = Helper.StripHtmlString(modelDocument.SelectSingleNode(String.Format(Queries.MDL_GetDecisionGateDescription, dgReferenceID)).InnerXml);

                            #region Determine phase and iteration
                            if (dgReferenceID.Equals("3650fb30c844c0") /*Angebot abgegeben*/ ||
                                dgReferenceID.Equals("56f6fb30c54fd7") /*Projekt definiert*/ ||
                                dgReferenceID.Equals("de21fb30c4aec0") /*Projekt definiert*/)
                            {
                                mainStatusNr = 0;
                            }
                            else
                            {
                                if (dgReferenceID.Equals("16970fb30c68166") /*Anforderungen festgelegt*/ ||
                                    dgReferenceID.Equals("645dfb30c8d591") /*Projekt beauftragt*/)
                                {
                                    mainStatusNr++;
                                    iterationNr = 0;
                                    inIteration = false;
                                }

                                if (dgReferenceID.Equals("6674fb30d05e5b") /*Projekt abgeschlossen*/)
                                {
                                    mainStatusNr = 99;
                                    iterationNr = 0;
                                    inIteration = false;
                                }

                                if (dgReferenceID.Equals("101d2fb30cff476") /*Iteration geplant*/)
                                {
                                    iterationNr++;
                                    inIteration = true;
                                }
                            }
                            #endregion

                            //Save phase and iteration
                            decisionGate.ExtendedData["DevPhase"] = mainStatusNr;
                            if (inIteration)
                                decisionGate.ExtendedData["DevIteration"] = iterationNr;
                        }
                        else
                        {
                            decisionGate.TypeName = decisionGate.Name;
                            decisionGate.Description = "";
                        }

                        //Add new milestone to list
                        Milestones.Add(decisionGate);
                    }
                    catch (Exception e)
                    {
                        log.AddEntryAndThrowException(string.Format(Language.Error_Parsing_Milestones, e.Message));
                    }
                }


                #region Write milestones' predecessors and missing DevPhases
                foreach (DecisionGate curDG in Milestones)
                {
                    //Predecessors
                    object predecessorIDList;
                    if (curDG.ExtendedData.TryGetValue("__VMXT_PredecessorList", out predecessorIDList))
                    {
                        curDG.Predecessors = new List<IMilestone>();

                        foreach (string curPredecessorID in predecessorIDList as List<string>)
                        {
                            foreach (DecisionGate innerDG in Milestones)
                            {
                                if (innerDG.Id.Equals(curPredecessorID, StringComparison.OrdinalIgnoreCase))
                                {
                                    curDG.Predecessors.Add(innerDG);
                                    break;
                                }
                            }
                        }
                    }
                }

                //Missing data
                int runCount = 0;
                bool runFailed;
                while(runCount < 2 * Milestones.Count)
                {
                    runCount++;
                    runFailed = false;

                    foreach (DecisionGate curDG in Milestones)
                    {
                        if (curDG.Predecessors.Count > 0)
                        {
                            try
                            {
                                if (!curDG.ExtendedData.ContainsKey("DevPhase"))
                                {
                                    curDG.ExtendedData["DevPhase"] = curDG.Predecessors[0].ExtendedData["DevPhase"];
                                    if(curDG.Predecessors[0].ExtendedData.ContainsKey("DevIteration"))
                                        curDG.ExtendedData["DevIteration"] = curDG.Predecessors[0].ExtendedData["DevIteration"];
                                }
                            }
                            catch
                            {
                                runFailed = true;
                            }
                        }
                    }

                    if (!runFailed)
                        break;
                }
                #endregion
            }
        }

        /// <summary>
        /// Loads milestones from a V-Model document.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadDecisionGates(XmlDocument modelDocument, Log log)
        {
            _Milestones = new List<IMilestone>();
            XmlNodeList milestoneList = modelDocument.SelectNodes(Queries.MDL_GetMilestones);
            foreach (XmlNode milestoneNode in milestoneList)
            {
                _Milestones.Add(new DecisionGate(milestoneNode));
            }
        }

        /// <summary>
        /// Loads activities.
        /// 
        /// Precondition: Dependencies have been loaded already.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadActivities(XmlDocument modelDocument, Log log)
        {
            if (Dependencies == null)
                throw new VMXTException(Language.Error_Parsing_LoadingOrderViolated);

            _Activities = new List<IActivity>();

            foreach (Dependency curDependency in _Dependencies)
            {
                if (curDependency is ProductActivityDependency)
                {
                    ProductActivityDependency paDependency = curDependency as ProductActivityDependency;

                    //Check whether this activity has already been loaded
                    bool alreadyExisting = false;
                    foreach (IActivity curActivity in _Activities)
                    {
                        if (curActivity.Id.Equals(paDependency.ActivityId, StringComparison.OrdinalIgnoreCase))
                        {
                            alreadyExisting = true;
                            break;
                        }
                    }

                    if (!alreadyExisting)
                    {
                        //Activitiy does not exist already - create it
                        XmlNode activityNode = modelDocument.SelectSingleNode(String.Format(Queries.MDL_GetActivityByID, paDependency.ActivityId));
                        if (activityNode != null)
                            _Activities.Add(new Activity(activityNode));
                    }
                }
            }
        }

        /// <summary>
        /// Loads tasks.
        /// 
        /// Precondition: Activities have been loaded already.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadTasks(XmlDocument modelDocument, Log log)
        {
            if (Activities == null)
                throw new VMXTException(Language.Error_Parsing_LoadingOrderViolated);

            _Tasks = new List<ITask>();

            XmlNodeList taskNodes = modelDocument.SelectNodes(Queries.MDL_GetTasks);
            foreach (XmlNode curTaskNode in taskNodes)
            {
                try
                {
                    string curBelongingActivity = curTaskNode.SelectSingleNode("AktivitätRef").Attributes["link"].Value;

                    //Check if this activity has been loaded and add task, if so
                    foreach (Activity curActivity in Activities)
                    {
                        if (curActivity.Id.Equals(curBelongingActivity, StringComparison.OrdinalIgnoreCase))
                        {
                            Tasks.Add(new Task(curTaskNode));
                            break;
                        }
                    }
                }
                catch { }
            }
        }

        /// <summary>
        /// Loads all roles from a given V-Model document.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadRoles(XmlDocument modelDocument, Log log)
        {
            _Roles = new List<IRole>();
            XmlNodeList roleList = modelDocument.SelectNodes(Queries.MDL_GetRoles);
            foreach (XmlNode roleNode in roleList)
            {
                _Roles.Add(new Role(roleNode));
            }
        }
        
        /// <summary>
        /// Loads all products from a given V-Model document.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadProducts(XmlDocument modelDocument, Log log)
        {
            _Products = new List<IProduct>();
            XmlNodeList productList = modelDocument.SelectNodes("//Produkt");
            foreach (XmlNode productNode in productList)
            {
                _Products.Add(new Product(productNode));
            }
        }

        /// <summary>
        /// Loads products from a VMP file.
        /// 
        /// Precondition: VBs have been loaded already.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="vmpDocument">VMP document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadProducts(XmlDocument modelDocument, XmlDocument vmpDocument, Log log)
        {
            if (ProjectVbIdList == null)
                throw new VMXTException(Language.Error_Parsing_LoadingOrderViolated);

            _Products = new List<IProduct>();

            foreach(string curVBId in ProjectVbIdList)
            {
                XmlNodeList curVBProductNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetProductsByVbId, curVBId));
                if (curVBProductNodes != null)
                {
                    foreach (XmlNode curProductNode in curVBProductNodes)
                    {
                        try
                        {
                            //Add it
                            _Products.Add(new Product(curProductNode));
                        }
                        catch
                        { }
                    }
                }
            }
        }

        /// <summary>
        /// Loads all disciplines from a given V-Model document.
        /// 
        /// Precondition: Products have been loaded.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadDisciplines(XmlDocument modelDocument, Log log)
        {
            if (Products == null)
                throw new VMXTException(Language.Error_Parsing_LoadingOrderViolated);

            _Disciplines = new List<IDiscipline>();
            XmlNodeList disciplineNodes = modelDocument.SelectNodes(Queries.MDL_GetDisciplines);
            foreach (XmlNode discNode in disciplineNodes)
            {
                try
                {
                    string curDisciplineId = discNode.Attributes["id"].Value;

                    //Check, if this discipline is used by any product
                    foreach (IProduct curProd in Products)
                    {
                        if (curProd.DisciplineId.Equals(curDisciplineId, StringComparison.OrdinalIgnoreCase))
                        {
                            //Yes -> load it.
                            _Disciplines.Add(new Discipline(discNode));
                            break;
                        }
                    }
                }
                catch { }
            }
        }

        /// <summary>
        /// Loads dependencies between existing objects from a given V-Model document.
        /// 
        /// Precondition: Products, VBs and decision gates have been loaded.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadDependencies(XmlDocument modelDocument, Log log)
        {
            if (Products == null || Milestones == null || ProjectVbIdList == null)
                throw new VMXTException(Language.Error_Parsing_LoadingOrderViolated);


            _Dependencies = new List<IProcessElementDependency>();

            foreach (string curVbId in ProjectVbIdList)
            {
                #region Activity - Product
                {
                    XmlNodeList activityToProductNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetProductActivityDependencies, curVbId));
                    foreach (XmlNode curAtoPNode in activityToProductNodes)
                    {
                        try
                        {
                            string productID = curAtoPNode.SelectSingleNode("ProduktRef").Attributes["link"].Value;

                            IProduct curProduct = this.GetProductByID(productID);
                            if (curProduct != null)
                            {
                                string newActivityId = curAtoPNode.SelectSingleNode("AktivitätRef").Attributes["link"].Value;

                                #region Do not create already existing dependencies
                                bool alreadyExisting = false;
                                foreach (IProcessElementDependency curDep in Dependencies)
                                {
                                    if (curDep is ProductActivityDependency)
                                    {
                                        ProductActivityDependency curPaDep = curDep as ProductActivityDependency;
                                        if (curPaDep.ProductId.Equals(productID, StringComparison.OrdinalIgnoreCase) && curPaDep.ActivityId.Equals(newActivityId, StringComparison.OrdinalIgnoreCase))
                                        {
                                            alreadyExisting = true;
                                            break;
                                        }
                                    }
                                }
                                if (alreadyExisting)
                                    continue;
                                #endregion

                                ProductActivityDependency newPADep = new ProductActivityDependency(productID, newActivityId);
                                newPADep.Id = curAtoPNode.Attributes["id"].Value;
                                newPADep.Name = curAtoPNode.SelectSingleNode("Name").InnerText;

                                _Dependencies.Add(newPADep);
                            }
                        }
                        catch { }
                    }
                }
                #endregion

                #region Product - Decision gate
                {
                    XmlNodeList productToDecisionGateNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetProductDecisionGateDependencies, curVbId));
                    foreach (XmlNode curPtoD in productToDecisionGateNodes)
                    {
                        try
                        {
                            string productID = curPtoD.SelectSingleNode("ProduktRef").Attributes["link"].Value;

                            //Find product, having this id
                            IProduct curProduct = this.GetProductByID(productID);
                            if (curProduct != null)
                            {
                                string decisionGateID = curPtoD.SelectSingleNode("EntscheidungspunktRef").Attributes["link"].Value;

                                //Find decision gate, having this id
                                IMilestone curDecisionGate = this.GetMilestoneByID(decisionGateID);
                                if (curDecisionGate != null)
                                {
                                    #region Do not create already existing dependencies
                                    bool alreadyExisting = false;
                                    foreach (IProcessElementDependency curDep in Dependencies)
                                    {
                                        if (curDep is ProductMilestoneDependency)
                                        {
                                            ProductMilestoneDependency curPmDep = curDep as ProductMilestoneDependency;
                                            if (curPmDep.ProductId.Equals(productID, StringComparison.OrdinalIgnoreCase) && curPmDep.MilestoneId.Equals(decisionGateID, StringComparison.OrdinalIgnoreCase))
                                            {
                                                alreadyExisting = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (alreadyExisting)
                                        continue;
                                    #endregion

                                    //Create dependency
                                    ProductMilestoneDependency newProductMilestonesDependency = new ProductMilestoneDependency(curProduct.Id, curDecisionGate.Id);
                                    newProductMilestonesDependency.Id = curPtoD.Attributes["id"].Value;
                                    newProductMilestonesDependency.Name = curPtoD.SelectSingleNode("Name").InnerText;

                                    //Add dependency
                                    Dependencies.Add(newProductMilestonesDependency);
                                }
                            }
                        }
                        catch { }
                    }
                }
                #endregion

                #region Product - Role
                AddProductDependencies<RoleResponsibleForProductDependency>(modelDocument.SelectNodes(string.Format(Queries.MDL_GetRoleResponsibleForProductDependencies, curVbId)));
                AddProductDependencies<RoleParticipatingInProductDependency>(modelDocument.SelectNodes(string.Format(Queries.MDL_GetRoleParticipatingInProductDependencies, curVbId)));
                #endregion

                #region Product content dependencies
                {
                    XmlNodeList dependentProductsNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetProductsContentDependencies, curVbId));
                    foreach (XmlNode curDP in dependentProductsNodes)
                    {
                        try
                        {
                            string depId = curDP.Attributes["id"].Value;
                            string depName = curDP.SelectSingleNode("Name").InnerText;

                            //Get correct name and description text, if available
                            string depDesc = "";
                            string depDescRaw = "";
                            try
                            {
                                XmlNode contentDependency = curDP.SelectSingleNode("InhaltlicheAbhängigkeitRef");
                                if (contentDependency != null)
                                {
                                    string contentDependencyID = contentDependency.Attributes["link"].Value;
                                    depId = contentDependencyID;
                                    XmlNode contentDependencyNode = curDP.OwnerDocument.SelectSingleNode(string.Format(Queries.MDL_GetContentDependencyByID, contentDependencyID));
                                    if (contentDependencyNode != null)
                                    {
                                        depName = contentDependencyNode.SelectSingleNode("Name").InnerText;

                                        depDescRaw = contentDependencyNode.SelectSingleNode("Beschreibung").InnerText;
                                        depDesc = Helper.StripHtmlString(depDescRaw);
                                    }
                                }
                            }
                            catch { }
                            //-----------------------------------------------------

                            //Get dependency product ids
                            List<string> dependendIDs = new List<string>();
                            foreach (XmlNode productRefNode in curDP.SelectNodes("ProduktRef"))
                            {
                                string curProdID = productRefNode.Attributes["link"].Value;
                                if (this.GetProductByID(curProdID) != null)
                                    dependendIDs.Add(curProdID);
                            }

                            //Create dependencies
                            foreach (string curProdID in dependendIDs)
                            {
                                foreach (string curDependentID in dependendIDs)
                                {
                                    if (curProdID != curDependentID)
                                    {
                                        ProductContentDependency newDep = new ProductContentDependency(curProdID, curDependentID);
                                        newDep.Id = depId;
                                        newDep.Name = depName;
                                        newDep.Description = depDesc;
                                        newDep.ExtendedData["DescriptionRaw"] = depDescRaw;
                                        _Dependencies.Add(newDep);
                                    }
                                }
                            }
                        }
                        catch { }
                    }
                }
                #endregion

                #region Product creation dependencies
                {
                    XmlNodeList dependentProductsNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetProductGenerationDestinationDependencies, curVbId));
                    foreach (XmlNode curDP in dependentProductsNodes)
                    {
                        try
                        {
                            //Get dependency id   ("Erzeugende Abhaengigkeit")
                            string connectorDependencyID = curDP.SelectSingleNode("ErzeugendeAbhängigkeitRef").Attributes["link"].Value;

                            //Get dependency
                            string connectorName = "";
                            string connectorDescriptionRaw = "";
                            string connectorDescription = "";

                            XmlNode dependencyConnectorNode = modelDocument.SelectSingleNode(string.Format(Queries.MDL_GetProductGenerationConnectorDependency, connectorDependencyID));
                            if (dependencyConnectorNode != null)
                            {
                                connectorName = dependencyConnectorNode.SelectSingleNode("Name").InnerText;
                                connectorDescriptionRaw = dependencyConnectorNode.SelectSingleNode("Beschreibung").InnerText;
                                connectorDescription = Helper.StripHtmlString(connectorDescriptionRaw);
                            }

                            //Get "Zu Produkt" nodes
                            XmlNodeList toProductIdNodes = curDP.SelectNodes("ProduktRef");
                            foreach (XmlNode curToProductIdNode in toProductIdNodes)
                            {
                                try
                                {
                                    string curToProductId = curToProductIdNode.Attributes["link"].Value;
                                    if (this.GetProductByID(curToProductId) == null) //Continue, if this product has not been loaded
                                        continue;


                                    XmlNodeList fromDependencyNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetProductGenerationSourceDependencies, connectorDependencyID));
                                    foreach (XmlNode curFromDependency in fromDependencyNodes)
                                    {
                                        XmlNodeList fromProductIdNodes = curFromDependency.ParentNode.SelectNodes("ProduktRef");
                                        foreach (XmlNode curFromProductIdNode in fromProductIdNodes)
                                        {
                                            string curFromProductId = curFromProductIdNode.Attributes["link"].Value;
                                            if (this.GetProductByID(curFromProductId) == null) //Continue, if this product has not been loaded
                                                continue;

                                            //Don't create already existing dependencies
                                            bool alreadyExisting = false;
                                            foreach (IProcessElementDependency curDepCheckObj in _Dependencies)
                                            {
                                                if (curDepCheckObj is GeneratingProductDependency)
                                                {
                                                    if ((curDepCheckObj as GeneratingProductDependency).ProductId.Equals(curToProductId) && (curDepCheckObj as GeneratingProductDependency).DependentProductId.Equals(curFromProductId))
                                                    {
                                                        alreadyExisting = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if (!alreadyExisting)
                                            {
                                                //Create and add new dependency
                                                GeneratingProductDependency newDependency = new GeneratingProductDependency(curToProductId, curFromProductId);
                                                newDependency.Id = connectorDependencyID;
                                                newDependency.Name = connectorName;
                                                newDependency.Description = connectorDescription;
                                                newDependency.ExtendedData["DescriptionRaw"] = connectorDescriptionRaw;

                                                _Dependencies.Add(newDependency);
                                            }
                                        }
                                    }
                                }
                                catch { }
                            }
                        }
                        catch { }
                    }
                }
                #endregion

                #region Product - Topic
                {

                    XmlNodeList ptDepNodes = modelDocument.SelectNodes(string.Format(Queries.MDL_GetTopics, curVbId));
                    foreach (XmlNode curDP in ptDepNodes)
                    {
                        try
                        {
                            string productID = curDP.SelectSingleNode("ProduktRef").Attributes["link"].Value;
                            if (this.GetProductByID(productID) == null) //Only create dependencies to loaded products
                                continue;

                            string topicID = curDP.SelectSingleNode("ThemaRef").Attributes["link"].Value;

                            #region Don't create already existing dependencies
		                    bool existing = false;
                            foreach (IProcessElementDependency curDep in _Dependencies)
                            {
                                if (curDep is ProductTopicDependency)
                                {
                                    ProductTopicDependency ptDep = curDep as ProductTopicDependency;
                                    if(ptDep.ProductId.Equals(productID, StringComparison.OrdinalIgnoreCase) && ptDep.TopicId.Equals(topicID, StringComparison.OrdinalIgnoreCase))
                                    {
                                        existing = true;
                                        break;
                                    }
                                }
                            }
                            if(existing)
                                continue; 
	                        #endregion

                            //Create and add dependency
                            ProductTopicDependency newDependency = new ProductTopicDependency(productID, topicID, 0);
                            newDependency.Id = curDP.Attributes["id"].Value;
                            newDependency.Name = curDP.SelectSingleNode("Name").InnerText;
                            _Dependencies.Add(newDependency);
                        }
                        catch { }
                    }
                }
                #endregion
            }
        }

        private void AddProductDependencies<T>(XmlNodeList productToRoleNodes) where T : RoleToProductDependency, new()
        {
            foreach (XmlNode curPtoR in productToRoleNodes)
            {
                try
                {
                    string productID = curPtoR.SelectSingleNode("ProduktRef").Attributes["link"].Value;

                    //Find product, having this id
                    IProduct curProduct = this.GetProductByID(productID);
                    if (curProduct != null)
                    {
                        string roleID = curPtoR.SelectSingleNode("RolleRef").Attributes["link"].Value;

                        //Find role, having this id
                        IRole curRole = this.GetRoleByID(roleID);
                        if (curRole != null)
                        {
                            #region Do not create already existing dependencies
                            bool alreadyExisting = false;
                            foreach (IProcessElementDependency curDep in Dependencies)
                            {
                                if (curDep is T)
                                {
                                    T curRrDep = curDep as T;
                                    if (curRrDep.ProductId.Equals(productID, StringComparison.OrdinalIgnoreCase) && curRrDep.RoleId.Equals(roleID, StringComparison.OrdinalIgnoreCase))
                                    {
                                        alreadyExisting = true;
                                        break;
                                    }
                                }
                            }
                            if (alreadyExisting)
                                continue;
                            #endregion

                            T newPRDependency = new T();
                            newPRDependency.RoleId = roleID;
                            newPRDependency.ProductId = productID;

                            newPRDependency.Id = curPtoR.Attributes["id"].Value;
                            newPRDependency.Name = curPtoR.SelectSingleNode("Name").InnerText;

                            _Dependencies.Add(newPRDependency);
                        }
                    }
                }
                catch { }
            }
        }

        /// <summary>
        /// Loads topics.
        /// 
        /// Precondition: Dependencies have been loaded already.
        /// </summary>
        /// <param name="modelDocument">V-Model document.</param>
        /// <param name="log">Log to be used.</param>
        private void LoadTopics(XmlDocument modelDocument, Log log)
        {
            if (_Dependencies == null)
                throw new VMXTException(Language.Error_Parsing_LoadingOrderViolated);

            _Topics = new List<ITopic>();

            foreach (IProcessElementDependency curDep in _Dependencies)
            {
                try
                {
                    if (curDep is ProductTopicDependency)
                    {
                        ProductTopicDependency curPTDep = curDep as ProductTopicDependency;

                        #region Check if this topic has already been loaded
                        bool alreadyLoaded = false;
                        foreach (ITopic curTopic in _Topics)
                        {
                            if (curPTDep.TopicId.Equals(curTopic.Id, StringComparison.OrdinalIgnoreCase))
                            {
                                alreadyLoaded = true;
                                break;
                            }
                        }
                        if (alreadyLoaded)
                            continue;
                        #endregion

                        XmlNode topicNode = modelDocument.SelectSingleNode(string.Format(Queries.MDL_GetTopicByID, curPTDep.TopicId));
                        if (topicNode == null)
                        {
                            _Dependencies.Remove(curPTDep);
                            continue;
                        }
                        //Add new topic
                        _Topics.Add(new Topic(topicNode));

                        //Insert order into dependency
                        curPTDep.Order = int.Parse(topicNode.SelectSingleNode("Nummer").InnerText);
                    }
                }
                catch { }
            }
        }
        #endregion

        #region IProcessProvider Members
        public List<IActivity> Activities
        {
            get
            {
                return (_Activities);
            }
        }

        public List<ITask> Tasks
        {
            get
            {
                return (_Tasks);
            }
        }

        public List<IProduct> Products
        {
            get
            {
                return (_Products);
            }
        }

        public List<IRole> Roles
        {
            get 
            {
                return (_Roles); 
            }
        }

        public List<ITopic> Topics
        {
            get
            {
                return (_Topics);
            }
        }

        public List<IDiscipline> Disciplines
        {
            get 
            {
                return (_Disciplines); 
            }
        }

        public List<IMilestone> Milestones
        {
            get 
            {
               return (_Milestones); 
            }
        }

        public List<IProcessElementDependency> Dependencies
        {
            get
            {
                return _Dependencies;
            }
        }

        public string Name
        {
            get
            {
                return _Name;
            }
        }

        public string Description
        {
            get
            {
                return _Description;
            }
        }

        public Dictionary<string, object> ExtendedData
        {
            get { return _ExtendedData; }
        }

        public string GetConfigPageName()
        {
            return "VModellConfigPage.xaml";
        }

        public void Serialize(XmlNode outputParentNode)
        {
            XmlDocument xmlDoc = outputParentNode.OwnerDocument;

            XmlNode settingsNode = xmlDoc.CreateElement("settings");
            outputParentNode.AppendChild(settingsNode);

            XmlAttribute modelFileAttribute = xmlDoc.CreateAttribute("modelFile");
            modelFileAttribute.Value = VModellFile;
            settingsNode.Attributes.Append(modelFileAttribute);

            XmlAttribute projectFileAttribute = xmlDoc.CreateAttribute("projectFile");
            projectFileAttribute.Value = ProjectFile;
            settingsNode.Attributes.Append(projectFileAttribute);
        }

        public void Deserialize(XmlNode inputParentNode)
        {
            XmlNode settingsNode = inputParentNode.SelectSingleNode("settings");

            try
            {
                _VModellFile = null;
                _VModellFile = settingsNode.Attributes["modelFile"].Value;
                if (!File.Exists(_VModellFile))
                    _VModellFile = null;
            }
            catch { }

            try
            {
                _ProjectFile = null;
                _ProjectFile = settingsNode.Attributes["projectFile"].Value;
                if (!File.Exists(_ProjectFile))
                    _ProjectFile = null;
            }
            catch { }
        }

        #endregion
    }
}